Skip to content

Follow RFC owner name rules in Name validator (wildcards + underscored labels)#50

Merged
ChiragAgg5k merged 2 commits into
mainfrom
feat-name-validator-rfc-wildcard-underscore
Jun 12, 2026
Merged

Follow RFC owner name rules in Name validator (wildcards + underscored labels)#50
ChiragAgg5k merged 2 commits into
mainfrom
feat-name-validator-rfc-wildcard-underscore

Conversation

@ChiragAgg5k

Copy link
Copy Markdown
Member

What does this PR do?

Updates Validator\Name to follow the DNS RFCs for owner names:

  • Wildcards (RFC 4592): * is now accepted as the entire leftmost label — *, *.example.com. Any other placement (f*o.com, a.*.b, *foo) is rejected with a new dedicated reason, FAILURE_REASON_INVALID_WILDCARD.
  • Underscored labels (RFC 8552): the previous allowlist (underscores only for SRV/TXT) is inverted into RECORD_TYPES_WITH_HOSTNAME_OWNER = [A, AAAA]. The no-underscore LDH rule (RFC 952, RFC 1123 §2.1) applies to host names, i.e. owners of address records; all other owner names follow the general domain name rules (RFC 2181 §11), where underscored labels are legal. This unblocks real-world names like selector1._domainkey DKIM CNAMEs, _acme-challenge and _dmarc CNAMEs.
  • Optional record type: the constructor argument is now ?int $recordType = null; null applies the general domain name rules, so callers can validate owner names of types the library has no code for yet (e.g. HTTPS, ALIAS). Existing call sites are unaffected.

Why?

In Appwrite Cloud this validator is being rolled out to all DNS record create/update endpoints after a production incident: a TXT record named google console (internal space) made an entire zone file unparseable and SERVFAILed the domain and all its subdomains. The validator correctly rejects that name, but as-is it also rejected ~7,500 legitimate production records (7,344 wildcard CNAMEs + ~150 underscored DKIM CNAMEs), so it could not be adopted without these changes.

Validated against all 46,674 DNS records in production (binary-collation distinct scan): exactly 11 records are rejected, every one genuinely malformed (internal/leading/trailing whitespace, pasted URLs, full-width , embedded @ label); zero legitimate records are rejected.

Test plan

  • vendor/bin/phpunit tests/e2e/DNS/Validator/NameTest.php — new testInvalidWildcard case, wildcard/underscore valid cases, strict host-name cases moved to TYPE_A, and the incident string google console as an explicit invalid case.
  • Full unit suite green (160 tests), Pint passes. PHPStan reports one pre-existing unrelated error (Server.php:285, Span::finish() arity).

Related PRs and Issues

  • Appwrite Cloud adoption tracked in CLO-4459 (internal)

Allow wildcard owner names ('*' as the entire leftmost label, RFC 4592)
and underscored labels (RFC 8552) for all record types except A/AAAA,
whose owner names must be valid host names (RFC 952, RFC 1123).
The record type constructor argument is now optional; null applies the
general domain name rules.
@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR updates Validator\Name to follow DNS RFCs more closely, fixing two categories of false rejections that blocked production adoption.

  • Wildcards (RFC 4592) are now accepted as the entire leftmost label (*, *.example.com); any other placement returns the new FAILURE_REASON_INVALID_WILDCARD. The detection logic strips the leading *. prefix, then checks for any remaining *, which correctly handles all edge cases including *.*.example.com.
  • The underscore allowlist is inverted into a denylist (RECORD_TYPES_WITH_HOSTNAME_OWNER = [A, AAAA]): only address records must follow the strict LDH hostname rule; all other record types follow RFC 2181 §11 general name rules, unblocking DKIM / DMARC / ACME underscore labels.
  • The constructor argument is now ?int $recordType = null, where null applies the general (permissive) rules.

Confidence Score: 4/5

Safe to merge — the wildcard and underscore logic is correct and well-tested, and the only change needed is a descriptive string update.

The core validation logic is sound: wildcard stripping correctly handles all placement variants, the allowlist-to-denylist inversion works as intended with null safety, and the new test cases cover the full range of RFC edge cases including the production-incident string. The only thing that needs attention is the FAILURE_REASON_GENERAL constant, which still describes the old allowlist behaviour after the logic inversion.

src/DNS/Validator/Name.php — the FAILURE_REASON_GENERAL constant description should be updated to reflect that underscores are now permitted by default and forbidden only for A/AAAA records.

Important Files Changed

Filename Overview
src/DNS/Validator/Name.php Inverts underscore allowlist to denylist (only A/AAAA require hostname format), adds RFC 4592 wildcard support with a dedicated failure reason, and makes the record type optional — all logically correct, with one stale general-failure description string.
tests/e2e/DNS/Validator/NameTest.php Adds testInvalidWildcard and extends testValid/testInvalid to cover wildcards, underscored DKIM/DMARC labels, null record type, and the production-incident 'google console' string — good coverage of the new paths.

Reviews (1): Last reviewed commit: "Follow RFC owner name rules in Name vali..." | Re-trigger Greptile

Comment thread src/DNS/Validator/Name.php Outdated
@ChiragAgg5k ChiragAgg5k merged commit c09469c into main Jun 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants